﻿#Region " Options "
Option Strict On
Option Explicit On
Option Compare Binary
#End Region

#Region " Imports "
Imports System
Imports System.Diagnostics
Imports System.Drawing
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Windows.Forms
Imports SAUpdaterExec.InternetShortcut
#End Region


#Region " Internet Shortcut Class "

''' <summary>Internet Shortcut Class.</summary>
Public Class InternetShortcut

#Region " Constants "
    Private Const CSIDL_DESKTOP = &H0
    Private Const CSIDL_STARTMENU = &HB
    Private Const CSIDL_STARTUP = &H7
    Private Const CSIDL_SENDTO = &H9
    '  Private Const CSIDL_DESKTOPDIRECTORY = &H10
    Private Const CSIDL_APPDATA = &H1A
#End Region

#Region " Enumeration "
    ''' <summary>Special folders path.</summary>
    Public Enum PathTo

        ''' <summary>The virtual folder that represents the Windows desktop, the root of the namespace.</summary>
        Desktop = CSIDL_DESKTOP
        ' ''' <summary>The file system directory used to physically store file objects on the desktop (not to be confused with the desktop folder itself). A typical path is C:\Documents and Settings\username\Desktop.</summary>
        '   Desktop_Directory = CSIDL_DESKTOPDIRECTORY
        ''' <summary>The file system directory that contains Start menu items. 
        ''' A typical path is C:\Documents and Settings\username\Start Menu.</summary>
        Start_Menu = CSIDL_STARTMENU
        ''' <summary>The file system directory that corresponds to the user's Startup program group. 
        ''' The system starts these programs whenever the associated user logs on. A typical path is C:\Documents and Settings\username\Start Menu\Programs\Startup.</summary>
        Startup = CSIDL_STARTUP
        ''' <summary>The file system directory that contains Send To menu items. 
        ''' A typical path is C:\Documents and Settings\username\SendTo.</summary>
        SendTo = CSIDL_SENDTO
        ''' <summary>The file system directory that contains Quick Launch shortcuts items. 
        ''' A typical path is C:\Documents and Settings\username\Application Data\Microsoft\Internet Explorer\Quick Launch.</summary>
        Quick_Launch = CSIDL_APPDATA
    End Enum
#End Region

#Region " Declaration "

    Private Declare Function GetPath Lib "shell32.dll" Alias "SHGetFolderPathA" (ByVal hwndOwner As Int32, ByVal nFolder As Int32, _
                                                ByVal hToken As Int32, ByVal dwFlags As Int32, ByVal lpszPath As String) As Int32

    Private Declare Unicode Function WritePrivateProfileString Lib "kernel32.dll" Alias "WritePrivateProfileStringW" _
      (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpString As String, ByVal lpFileName As String) As Integer

    Private Declare Unicode Function FlushPrivateProfileString Lib "kernel32.dll" Alias "WritePrivateProfileStringW" _
      (ByVal lpApplicationName As Integer, ByVal lpKeyName As Integer, ByVal lpString As Integer, ByVal lpFileName As String) As Integer
    Dim strFilename As String

    ' Constructor, accepting a filename
    Private Sub New(ByVal Filename As String)
        strFilename = Filename
    End Sub

    ' Read-only filename property
    ReadOnly Property FileName() As String
        Get
            Return strFilename
        End Get
    End Property

#End Region

#Region " Functions "

    ''' <summary>This function will create internet shortcut.</summary>
    ''' <param name="ShortcutName">Name of shortcut.</param>
    ''' <param name="Url">Enter a link address. Ex: "www.exemple.com".</param>
    ''' <param name="DestinationShortcut">Target Path where you want to place shortcut. Use "Target(PathTo...)" function for default path constants.</param>
    ''' <param name="StartMenuSubFolder">Enter name for creating folder in Start Menu. This is recommended only if you choose Sart_Menu,
    ''' leave this empty if you choose another path, for exemple "Desktop" or if you don't want to create folder.</param>
    Public Shared Function AddUrlShortcut(ByVal ShortcutName As String, ByVal Url As String, _
                                          ByVal DestinationShortcut As String, ByVal StartMenuSubFolder As String) As String

        If DestinationShortcut = Target(PathTo.Start_Menu) = True Then
            My.Computer.FileSystem.CreateDirectory(Target(PathTo.Start_Menu) + "\" + StartMenuSubFolder)
        End If

        If DestinationShortcut = Target(PathTo.Desktop) = True Then
            StartMenuSubFolder = ""
        ElseIf DestinationShortcut = Target(PathTo.Quick_Launch) = True Then
            StartMenuSubFolder = ""
        ElseIf DestinationShortcut = Target(PathTo.SendTo) = True Then
            StartMenuSubFolder = ""
        ElseIf DestinationShortcut = Target(PathTo.Startup) = True Then
            StartMenuSubFolder = ""
        End If

        If DestinationShortcut = Target(PathTo.Quick_Launch) Then
            Dim SaveShortcutQuickLaunch As New InternetShortcut(DestinationShortcut _
                                               + "\" + "Microsoft\Internet Explorer\Quick Launch" + "\" + _
                                               StartMenuSubFolder.ToString + "\" + ShortcutName.ToString + ".url")
            SaveShortcutQuickLaunch.WriteString("InternetShortcut", "URL", Url)
        Else
            Dim SaveShortcut As New InternetShortcut(DestinationShortcut + "\" + StartMenuSubFolder.ToString _
                                                                         + "\" + ShortcutName.ToString + ".url")
            SaveShortcut.WriteString("InternetShortcut", "URL", Url)
        End If
        Return ""
    End Function

    ''' <summary>This function is a special folders path.</summary>
    ''' <param name="SpecialPath">Choose one of this: "Desktop", "Start Menu", "Startup", "SendTo", "Quick Launch".</param>
    Public Shared Function Target(ByVal SpecialPath As PathTo) As String
        Dim szString As String = Space(260)
        Dim nNumber As Int32
        nNumber = GetPath(0, SpecialPath, 0, 0, szString)
        If nNumber <> 0 Then
            Return ""
        Else
            nNumber = InStr(szString, vbNullChar)
            If nNumber > 0 Then
                Return Left(szString, nNumber - 1)
            Else
                Return szString
            End If
        End If
    End Function

    Private Sub WriteString(ByVal Section As String, ByVal Key As String, ByVal Value As String)
        WritePrivateProfileString(Section, Key, Value, strFilename)
        Flush()
    End Sub

    Private Sub Flush()
        FlushPrivateProfileString(0, 0, 0, strFilename)
    End Sub

#End Region

End Class
#End Region

#Region " Application Shortcut Calss"

''' <summary>Application Shortcut Calss.</summary>
Public Class AppShortcut
    Implements IDisposable

    ''' <summary>This function will create application lnk shortcut.</summary>
    ''' <param name="ShortcutName">Name of application shortcut.</param>
    ''' <param name="AppTarget">Target of application you want to create shortcut. Properties name is "Target:". 
    ''' Ex: "C:\Program Files\Application\exemple.exe" or any extension.</param>
    ''' <param name="StartIn">Application path target, not file, only the path. Ex: "C:\Program Files\Application\".</param>
    ''' <param name="Argument">Command line for application. Ex: "-cmdline" or "/cmdline".</param>
    ''' <param name="Comment">Description of shortcut. Properties name is "Comment:".</param>
    ''' <param name="nIcon">Icon path for shortcut, supported extension ".exe", ".ico", ".dll".</param>
    ''' <param name="nIconindex">If your application ".exe" or ".dll" file, contains multiple icons, then use index to point the icon you want to display on shortcut. 
    ''' Default index is "0".</param>
    ''' <param name="Run">Select run mode for application. Ex: "Normal Window" is Default, "Minimized" running application minimized to taskbar, 
    ''' "Maximized" running application in maximized window. "Hidden" mode is unsupported.</param>
    ''' <param name="DestinationShortcut">Target Path where you want to place shortcut. Use "Target(PathTo...)" function for default path constants.</param>
    ''' <param name="StartMenuSubFolder">Enter name for creating folder in Start Menu. This is recommended only if you choose Sart_Menu,
    ''' leave this empty if you choose another path, for exemple "Desktop" or if you don't want to create folder.</param>
    Public Shared Function AddLnkShortcut(ByVal ShortcutName As String, ByVal AppTarget As String, ByVal StartIn As String, _
                                  ByVal Argument As String, ByVal Comment As String, ByVal nIcon As String, _
                                  ByVal nIconindex As Integer, ByVal Run As ProcessWindowStyle, _
                                  ByVal DestinationShortcut As String, ByVal StartMenuSubFolder As String) As String

        If DestinationShortcut = Target(PathTo.Start_Menu) = True Then
            My.Computer.FileSystem.CreateDirectory(Target(PathTo.Start_Menu) + "\" + StartMenuSubFolder)
        End If

        If DestinationShortcut = Target(PathTo.Desktop) = True Then
            StartMenuSubFolder = ""
        ElseIf DestinationShortcut = Target(PathTo.Quick_Launch) = True Then
            StartMenuSubFolder = ""
        ElseIf DestinationShortcut = Target(PathTo.SendTo) = True Then
            StartMenuSubFolder = ""
        ElseIf DestinationShortcut = Target(PathTo.Startup) = True Then
            StartMenuSubFolder = ""
        End If


        If DestinationShortcut = Target(PathTo.Quick_Launch) = True Then
            Dim SaveShortcutQuickLaunch As AppShortcut = New AppShortcut(DestinationShortcut + "\" + _
                                                         "Microsoft\Internet Explorer\Quick Launch" + "\" _
                                                         + StartMenuSubFolder + "\" + ShortcutName + ".lnk")
            With SaveShortcutQuickLaunch
                .Path = AppTarget
                .WorkingDirectory = StartIn
                .Arguments = Argument
                .Description = Comment
                .IconPath = nIcon
                .IconIndex = CInt(nIconindex)
                .WindowStyle = CType(Run, ProcessWindowStyle)
                .Save()
            End With
        Else

            Dim SavelnkShortcut As AppShortcut = New AppShortcut(DestinationShortcut + "\" + StartMenuSubFolder + "\" + ShortcutName + ".lnk")
            With SavelnkShortcut
                .Path = AppTarget
                .WorkingDirectory = StartIn
                .Arguments = Argument
                .Description = Comment
                .IconPath = nIcon
                .IconIndex = CInt(nIconindex)
                .WindowStyle = CType(Run, ProcessWindowStyle)
                .Save()
            End With
        End If
        Return ""
    End Function


#Region " Interface "
    <Flags()> _
    Private Enum SLR_FLAGS
        SLR_NO_UI = &H1
        SLR_ANY_MATCH = &H2
        SLR_UPDATE = &H4
        SLR_NOUPDATE = &H8
        SLR_NOSEARCH = &H10
        SLR_NOTRACK = &H20
        SLR_NOLINKINFO = &H40
        SLR_INVOKE_MSI = &H80
    End Enum

    ' IShellLink.GetPath fFlags
    <Flags()> _
    Private Enum SLGP_FLAGS
        SLGP_SHORTPATH = &H1
        SLGP_UNCPRIORITY = &H2
        SLGP_RAWPATH = &H4
    End Enum

    <ObsoleteAttribute>
    <StructLayoutAttribute(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> Private Structure WIN32_FIND_DATAA
        Private dwFileAttributes As Integer
        Private ftCreationTime As FILETIME
        Private ftLastAccessTime As FILETIME
        Private ftLastWriteTime As FILETIME
        Private nFileSizeHigh As Integer
        Private nFileSizeLow As Integer
        Private dwReserved0 As Integer
        Private dwReserved1 As Integer
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)> Private cFileName As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Private cAlternateFileName As String
        Private Const MAX_PATH As Integer = 260
    End Structure

    <ObsoleteAttribute>
        <StructLayoutAttribute(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> Private Structure WIN32_FIND_DATAW
        Private dwFileAttributes As Integer
        Private ftCreationTime As FILETIME
        Private ftLastAccessTime As FILETIME
        Private ftLastWriteTime As FILETIME
        Private nFileSizeHigh As Integer
        Private nFileSizeLow As Integer
        Private dwReserved0 As Integer
        Private dwReserved1 As Integer
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)> Private cFileName As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Private cAlternateFileName As String
        Private Const MAX_PATH As Integer = 260
    End Structure

    < _
      ComImport(), _
      InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000010B-0000-0000-C000-000000000046") _
    > _
    Private Interface IPersistFile

#Region "Methods inherited from IPersist"

        Sub GetClassID(<Out()> ByRef pClassID As Guid)
#End Region

        <PreserveSig()> _
        Function IsDirty() As Integer

        Sub Load( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszFileName As String, ByVal dwMode As Integer)

        Sub Save( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszFileName As String, _
          <MarshalAs(UnmanagedType.Bool)> ByVal fRemember As Boolean)

        Sub SaveCompleted( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszFileName As String)

        Sub GetCurFile(ByRef ppszFileName As IntPtr)

    End Interface

    < _
      ComImport(), _
      InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
      Guid("000214EE-0000-0000-C000-000000000046") _
    > _
    Private Interface IShellLinkA

        <ObsoleteAttribute>
        Sub GetPath( _
          <Out(), MarshalAs(UnmanagedType.LPStr)> ByVal pszFile As StringBuilder, ByVal cchMaxPath As Integer, _
          <Out()> ByRef pfd As WIN32_FIND_DATAA, ByVal fFlags As SLGP_FLAGS)

        Sub GetIDList(ByRef ppidl As IntPtr)

        Sub SetIDList(ByVal pidl As IntPtr)

        Sub GetDescription( _
          <Out(), MarshalAs(UnmanagedType.LPStr)> ByVal pszName As StringBuilder, ByVal cchMaxName As Integer)

        Sub SetDescription( _
          <MarshalAs(UnmanagedType.LPStr)> ByVal pszName As String)

        Sub GetWorkingDirectory( _
          <Out(), MarshalAs(UnmanagedType.LPStr)> ByVal pszDir As StringBuilder, ByVal cchMaxPath As Integer)

        Sub SetWorkingDirectory( _
          <MarshalAs(UnmanagedType.LPStr)> ByVal pszDir As String)

        Sub GetArguments( _
          <Out(), MarshalAs(UnmanagedType.LPStr)> ByVal pszArgs As StringBuilder, ByVal cchMaxPath As Integer)

        Sub SetArguments( _
          <MarshalAs(UnmanagedType.LPStr)> ByVal pszArgs As String)

        Sub GetHotkey(ByRef pwHotkey As Short)

        Sub SetHotkey(ByVal wHotkey As Short)

        Sub GetShowCmd(ByRef piShowCmd As Integer)

        Sub SetShowCmd(ByVal iShowCmd As Integer)

        Sub GetIconLocation( _
          <Out(), MarshalAs(UnmanagedType.LPStr)> ByVal pszIconPath As StringBuilder, _
          ByVal cchIconPath As Integer, ByRef piIcon As Integer)

        Sub SetIconLocation( _
          <MarshalAs(UnmanagedType.LPStr)> ByVal pszIconPath As String, ByVal iIcon As Integer)

        Sub SetRelativePath( _
          <MarshalAs(UnmanagedType.LPStr)> ByVal pszPathRel As String, ByVal dwReserved As Integer)

        Sub Resolve(ByVal hwnd As IntPtr, ByVal fFlags As SLR_FLAGS)

        Sub SetPath( _
          <MarshalAs(UnmanagedType.LPStr)> ByVal pszFile As String)

    End Interface

    < _
      ComImport(), _
      InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown), _
      Guid("000214F9-0000-0000-C000-000000000046") _
    > _
    Private Interface IShellLinkW

        <ObsoleteAttribute>
        Sub GetPath( _
          <Out(), MarshalAs(UnmanagedType.LPWStr)> ByVal pszFile As StringBuilder, ByVal cchMaxPath As Integer, _
          <Out()> ByRef pfd As WIN32_FIND_DATAW, ByVal fFlags As SLGP_FLAGS)

        Sub GetIDList(ByRef ppidl As IntPtr)

        Sub SetIDList(ByVal pidl As IntPtr)

        Sub GetDescription( _
          <Out(), MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As StringBuilder, ByVal cchMaxName As Integer)

        Sub SetDescription( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String)

        Sub GetWorkingDirectory( _
          <Out(), MarshalAs(UnmanagedType.LPWStr)> ByVal pszDir As StringBuilder, ByVal cchMaxPath As Integer)

        Sub SetWorkingDirectory( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszDir As String)

        Sub GetArguments( _
          <Out(), MarshalAs(UnmanagedType.LPWStr)> ByVal pszArgs As StringBuilder, ByVal cchMaxPath As Integer)

        Sub SetArguments( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszArgs As String)

        Sub GetHotkey(ByRef pwHotkey As Short)

        Sub SetHotkey(ByVal wHotkey As Short)

        Sub GetShowCmd(ByRef piShowCmd As Integer)

        Sub SetShowCmd(ByVal iShowCmd As Integer)

        Sub GetIconLocation( _
          <Out(), MarshalAs(UnmanagedType.LPWStr)> ByVal pszIconPath As StringBuilder, _
          ByVal cchIconPath As Integer, ByRef piIcon As Integer)

        Sub SetIconLocation( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszIconPath As String, ByVal iIcon As Integer)

        Sub SetRelativePath( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszPathRel As String, ByVal dwReserved As Integer)

        Sub Resolve(ByVal hwnd As IntPtr, ByVal fFlags As SLR_FLAGS)

        Sub SetPath( _
          <MarshalAs(UnmanagedType.LPWStr)> ByVal pszFile As String)

    End Interface
#End Region

#Region " IShellLinkA "
    Private Const INFOTIPSIZE As Integer = 1024
    Private Const MAX_PATH As Integer = 260
    Private Const SW_SHOWNORMAL As Integer = 1
    Private Const SW_SHOWMINIMIZED As Integer = 2
    Private Const SW_SHOWMAXIMIZED As Integer = 3
    Private Const SW_SHOWMINNOACTIVE As Integer = 7

#If [UNICODE] Then
    Private m_Link As IShellLinkW
#Else
    Private m_Link As IShellLinkA
#End If
    Private m_sPath As String

    ' linkPath: Path to new or existing shortcut file (.lnk).
    Private Sub New(ByVal linkPath As String)

        Dim pf As IPersistFile
        Dim CLSID_ShellLink As Guid = New Guid("00021401-0000-0000-C000-000000000046")
        Dim tShellLink As Type

        ' Workaround for VB.NET compiler bug with ComImport classes
        '#If [UNICODE] Then
        '      m_Link = CType(New ShellLink(), IShellLinkW)
        '#Else
        '      m_Link = CType(New ShellLink(), IShellLinkA)
        '#End If
        tShellLink = Type.GetTypeFromCLSID(CLSID_ShellLink)
#If [UNICODE] Then
      m_Link = CType(Activator.CreateInstance(tShellLink), IShellLinkW)
#Else
        m_Link = CType(Activator.CreateInstance(tShellLink), IShellLinkA)
#End If

        m_sPath = linkPath

        If File.Exists(linkPath) Then
            pf = CType(m_Link, IPersistFile)
            pf.Load(linkPath, 0)
        End If

    End Sub

    Private Sub Dispose() Implements IDisposable.Dispose
        If m_Link Is Nothing Then Exit Sub
        Marshal.ReleaseComObject(m_Link)
        m_Link = Nothing
    End Sub

    ' Gets or sets the argument list of the shortcut.
    Private Property Arguments() As String
        Get
            Dim sb As StringBuilder = New StringBuilder(INFOTIPSIZE)
            m_Link.GetArguments(sb, sb.Capacity)
            Return sb.ToString()
        End Get
        Set(ByVal Value As String)
            m_Link.SetArguments(Value)
        End Set
    End Property

    ' Gets or sets a description of the shortcut.
    Private Property Description() As String
        Get
            Dim sb As StringBuilder = New StringBuilder(INFOTIPSIZE)
            m_Link.GetDescription(sb, sb.Capacity)
            Return sb.ToString()
        End Get
        Set(ByVal Value As String)
            m_Link.SetDescription(Value)
        End Set
    End Property

    ' Gets or sets the working directory (aka start in directory) of the shortcut.
    Private Property WorkingDirectory() As String
        Get
            Dim sb As StringBuilder = New StringBuilder(MAX_PATH)
            m_Link.GetWorkingDirectory(sb, sb.Capacity)
            Return sb.ToString
        End Get
        Set(ByVal Value As String)
            m_Link.SetWorkingDirectory(Value)
        End Set
    End Property

    ' If Path returns an empty string, the shortcut is associated with
    ' a PIDL instead, which can be retrieved with IShellLink.GetIDList().
    ' This is beyond the scope of this wrapper class.
    ' Gets or sets the target path of the shortcut.
    Private Property Path() As String
        <ObsoleteAttribute>
        Get
#If [UNICODE] Then
                    Dim wfd As WIN32_FIND_DATAW
#Else
            Dim wfd As WIN32_FIND_DATAA
#End If

            Dim sb As StringBuilder = New StringBuilder(MAX_PATH)
            m_Link.GetPath(sb, sb.Capacity, wfd, SLGP_FLAGS.SLGP_UNCPRIORITY)
            Return sb.ToString
        End Get
        Set(ByVal Value As String)
            m_Link.SetPath(Value)
        End Set
    End Property

    ' Gets or sets the path of the Icon assigned to the shortcut.
    Private Property IconPath() As String
        Get
            Dim sb As StringBuilder = New StringBuilder(MAX_PATH)
            Dim nIconIdx As Integer
            m_Link.GetIconLocation(sb, sb.Capacity, nIconIdx)
            Return sb.ToString()
        End Get
        Set(ByVal Value As String)
            m_Link.SetIconLocation(Value, IconIndex)
        End Set
    End Property

    ' Gets or sets the index of the Icon assigned to the shortcut.
    ' Set to zero when the IconPath property specifies a .ICO file.
    Private Property IconIndex() As Integer
        Get
            Dim sb As StringBuilder = New StringBuilder(MAX_PATH)
            Dim nIconIdx As Integer
            m_Link.GetIconLocation(sb, sb.Capacity, nIconIdx)
            Return nIconIdx
        End Get
        Set(ByVal Value As Integer)
            m_Link.SetIconLocation(IconPath, Value)
        End Set
    End Property

    ' Retrieves the Icon of the shortcut as it will appear in Explorer.
    ' Use the IconPath and IconIndex properties to change it.
    Private ReadOnly Property Icon() As Icon
        Get
            Dim sb As StringBuilder = New StringBuilder(MAX_PATH)
            Dim nIconIdx As Integer
            Dim hIcon, hInst As IntPtr
            Dim ico, clone As Icon

            m_Link.GetIconLocation(sb, sb.Capacity, nIconIdx)

            hInst = Marshal.GetHINSTANCE(Me.GetType().Module)
            hIcon = Native.ExtractIcon(hInst, sb.ToString(), nIconIdx)
            If hIcon.ToInt32() = 0 Then Return Nothing

            ' Return a cloned Icon, because we have to free the original ourself.
            ico = Icon.FromHandle(hIcon)
            clone = CType(ico.Clone(), Icon)
            ico.Dispose()
            Native.DestroyIcon(hIcon)
            Return clone
        End Get
    End Property

    ' Gets or sets the System.Diagnostics.ProcessWindowStyle value
    ' that decides the initial show state of the shortcut target. Note that
    ' ProcessWindowStyle.Hidden is not a valid property value.
    Private Property WindowStyle() As ProcessWindowStyle
        Get
            Dim nWS As Integer
            m_Link.GetShowCmd(nWS)

            Select Case nWS
                Case SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE
                    Return ProcessWindowStyle.Minimized
                Case SW_SHOWMAXIMIZED
                    Return ProcessWindowStyle.Maximized
                Case Else
                    Return ProcessWindowStyle.Normal
            End Select
        End Get
        Set(ByVal Value As ProcessWindowStyle)
            Dim nWS As Integer

            Select Case Value
                Case ProcessWindowStyle.Normal
                    nWS = SW_SHOWNORMAL
                Case ProcessWindowStyle.Minimized
                    nWS = SW_SHOWMINNOACTIVE
                Case ProcessWindowStyle.Maximized
                    nWS = SW_SHOWMAXIMIZED
                Case Else ' ProcessWindowStyle.Hidden
                    Throw New ArgumentException("Unsupported ProcessWindowStyle value.")
            End Select
            m_Link.SetShowCmd(nWS)
        End Set
    End Property

    ' Gets or sets the hotkey for the shortcut.
    Private Property Hotkey() As Keys
        Get
            Dim wHotkey As Short
            Dim dwHotkey As Integer

            m_Link.GetHotkey(wHotkey)

            ' Convert from IShellLink 16-bit format to Keys enumeration 32-bit value
            ' IShellLink: &HMMVK
            ' Keys:  &H00MM00VK        
            '   MM = Modifier (Alt, Control, Shift)
            '   VK = Virtual key code
            dwHotkey = (wHotkey And &HFF00I) * &H100I Or (wHotkey And &HFFI)
            Return CType(dwHotkey, Keys)

        End Get
        Set(ByVal Value As Keys)
            Dim wHotkey As Short

            If (Value And Keys.Modifiers) = 0 Then
                Throw New ArgumentException("Hotkey must include a modifier key.")
            End If

            ' Convert from Keys enumeration 32-bit value to IShellLink 16-bit format
            ' IShellLink: &HMMVK
            ' Keys:  &H00MM00VK        
            '   MM = Modifier (Alt, Control, Shift)
            '   VK = Virtual key code
            wHotkey = CShort(CInt(Value And Keys.Modifiers) \ &H100) Or CShort(Value And Keys.KeyCode)
            m_Link.SetHotkey(wHotkey)

        End Set
    End Property

    ' Saves the shortcut to disk.
    Private Sub Save()
        Dim pf As IPersistFile = CType(m_Link, IPersistFile)
        pf.Save(m_sPath, True)
    End Sub

    ' Returns a reference to the internal ShellLink object,
    ' which can be used to perform more advanced operations
    ' not supported by this wrapper class, by using the
    ' IShellLink interface directly.
    Private ReadOnly Property ShellLink() As Object
        Get
            Return m_Link
        End Get
    End Property
#End Region

#Region "Native Win32 API functions"
    Private Class Native

        <DllImport("shell32.dll", CharSet:=CharSet.Auto)> _
        Public Shared Function ExtractIcon(ByVal hInst As IntPtr, ByVal lpszExeFileName As String, ByVal nIconIndex As Integer) As IntPtr
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
        End Function

    End Class
#End Region

End Class

#End Region